package hermesV2.services.P2P_Service;

import hermesV2.Message;
import hermesV2.PlaceAddress;
import hermesV2.agent.CloneException;
import hermesV2.agent.CommunicationException;
import hermesV2.agent.Identificator;
import hermesV2.agent.InteractionContainer;
import hermesV2.agent.MigrationException;
import hermesV2.agent.UserAgent;
import hermesV2.services.P2P_ServiceAgent;

import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import android.util.Log;

public class DeathAgent extends UserAgent {
  

/**
	 * 
	 */
	private static final long serialVersionUID = 3737497582715219329L;
/**
	 * 
	 */
/**
	 * 
	 */
	private Vector<PlaceAddress> peers;
	private Vector<PlaceAddress> peersUpdated;
	private  Vector<String> peers_online;
    private  Vector<Date> peers_eventTime;
    private PlaceAddress currentPlace; // where i am going
    private PlaceAddress previousPlace; // where i come from
    private PlaceAddress endHop;
    
public DeathAgent(String agentName) {
        super("DeathAgent");
        peers= new Vector<PlaceAddress>();// peers list without offline peers
        
        peersUpdated = new Vector<PlaceAddress>(); // peers list with offline peers 
    	peers_online = new Vector<String> ();
        peers_eventTime  = new  Vector<Date>();
  }

  
  public void init() {
  
	  reception(); 
	  previousPlace= currentPlace= this.getIdentificator().getBornPlaceAddress();
	P2P_ServiceAgent.writeLog("p2p",   "[DeathAgent] just born here");
	  /*Find the peer to peer Service Identificator*/
	  Identificator serviceId = getServiceIdentificator("PeerToPeer_v1.0");
		loginToService(serviceId, "ezio", "ezio");
	  if (serviceId != null){
		 try{
		  InteractionContainer ic = new InteractionContainer(getServiceProtocol(serviceId));
		  ic.makeInteraction("AskPeersList", "");
			sendMessageToServiceAgent(new Message<InteractionContainer>(getIdentificator(), serviceId, ic));
			Message<?> response = getMessageSynch();
			peersUpdated = (Vector<PlaceAddress>) ((InteractionContainer)response.getObject()).getParameter("PeersList");
			peers_online = (Vector<String>) ((InteractionContainer)response.getObject()).getParameter("AreOnline");
			peers_eventTime = (Vector<java.util.Date>) ((InteractionContainer)response.getObject()).getParameter("EventTime");
			 //remove offline peers
	    	 for (int i=0; i<peersUpdated.size();i++)
	    	 {
	    		if (peers_online.get(i).equals("true"))
	    		 {peers.add(peersUpdated.get(i));}
	    	 }
			P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]i have the full list");
		  } catch (CommunicationException e) {P2P_ServiceAgent.writeLog("p2p",   "[DeathAgent]Error "+e);}
			try{
				if (middle()!=null) 
				 {P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to the middle "+middle().getPort()+":"+middle().getIp());
				  clone("goToTheMiddle", "clone_middle");
				 }
				if (first()!=null) 
				 {P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to first "+first().getPort()+":"+first().getIp());
				   clone("goToTheFirst", "clone_first");
				 }
			    }  catch (CloneException ce) {P2P_ServiceAgent.writeLog("p2p", "Error "+ce); }
			 this.dead();
	  }
	  else {P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]service agent PeerToPeer_v1.0 not found");}
	  
	  this.dead();	
  }
  

  
  
  
  public void goToTheFirst(){
	  try{
		  previousPlace = currentPlace;
		  currentPlace =first();	  
	        this.move(currentPlace, "afterFirst");
	    } catch (MigrationException me) 
	    {
	    	me.printStackTrace();
	    	Log.i("p2p", "[DeathAgent]MigrationException to first" + me);
	    	P2P_ServiceAgent.writeLog("p2p", "[DeathAgent] "+currentPlace+" doesn't answer. try next");
	    	offlinePeer(currentPlace, Calendar.getInstance().getTime());
	    	currentPlace = previousPlace;
	    	if (first()!=null)
	    	{
	  		  P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to first "+first().getPort()+":"+first().getIp());
	    	  goToTheFirst();
	    	}
	    }
  }
  
  
  public void goToTheMiddle(){
	try{
		previousPlace = currentPlace;
		currentPlace=middle();
        this.move(currentPlace, "afterMiddle");
    } catch (MigrationException me) 
    {
    	me.printStackTrace();
    	Log.i("p2p", "[DeathAgent]MigrationException to middle" + me);
    	P2P_ServiceAgent.writeLog("p2p", "[DeathAgent] "+currentPlace+" doesn't answer. try next");
    	offlinePeer(currentPlace, Calendar.getInstance().getTime());
    	currentPlace = previousPlace;
    	if (middle()!=null)
    	{
  		  P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to middle "+middle().getPort()+":"+middle().getIp());
  		  goToTheMiddle();
    	}
    
    }
  }
  
  public void goToNext(){
	  try{
	  if (endHop!=null)
	  { 
		  if (!currentPlace.equals(endHop))
		  {
			  if (next()!=null)
			     {  
				  previousPlace = currentPlace;
				  currentPlace=next();
				  P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to the next "+currentPlace.getPort()+":"+currentPlace.getIp());
				  this.move(currentPlace, "updateList");
				 }
		  }
	  }
	  else
	  {
		if (next() != null)
		 {
			previousPlace = currentPlace;
			currentPlace=next();
			P2P_ServiceAgent.writeLog("p2p", "[DeathAgent]go to the next "+currentPlace.getPort()+":"+currentPlace.getIp());
			this.move(currentPlace, "updateList");
		 }
	  }
	  }catch (MigrationException ex)
	  {
		  ex.printStackTrace();
		  P2P_ServiceAgent.writeLog("p2p", "[DeathAgent] "+currentPlace+" doesn't answer. try next");
		  offlinePeer(currentPlace, Calendar.getInstance().getTime());
	    	currentPlace = previousPlace;
	  		goToNext();
	  }
	 this.dead();
  }
  
  public void afterMiddle(){
	  endHop=null; //go on until the last
	  updateList();
	  }
  
  public void afterFirst(){
	  endHop = middle();// go on until the middle
	  updateList();
	  }
  
  
 public void updateList()
 {
	  reception(); 
	  loginToService(getServiceIdentificator("PeerToPeer_v1.0"), "ezio", "ezio");
	  P2P_ServiceAgent.writeLog("p2p",  "[DeathAgent]moved here from "+previousPlace.getIp()+":"+previousPlace.getPort());
	  Identificator serviceId = getServiceIdentificator("PeerToPeer_v1.0");
	  InteractionContainer ic = new InteractionContainer(getServiceProtocol(serviceId));
	  Object [] params = new Object[3];
	  params[0] = peersUpdated; // with offline peers set to false
	  params[1] = peers_online;
	  params[2] = peers_eventTime;
	  ic.makeInteraction("UpdateList", params);
 	  try {
		   sendMessageToServiceAgent(new Message<InteractionContainer>(getIdentificator(), serviceId, ic));
		   Message<?> response = getMessageSynch();
		   P2P_ServiceAgent.writeLog("p2p",  "[DeathAgent]response = " + ((InteractionContainer)response.getObject()).getParameter("Response"));
	      } 
 	  catch (CommunicationException e) {P2P_ServiceAgent.writeLog("p2p",   "[DeathAgent]Error "+e);}
 	 goToNext();
 }  
  
  
  
  
  PlaceAddress next()
  {
  int i=0;
   while(!peers.get(i).equals(currentPlace))
   {
    i++;
   }
  if (i == peers.size()-1) {return null;} // i'm the last, i have not next
  else {return peers.get(i+1);}
  }






  //index of the middle peer (to notify) in the current list
  PlaceAddress middle()
  {
   int len = peers.size();
   int mid; 
   if (len%2==0) {mid= len/2;}
   else {mid= (len+1)/2;}
   if (!peers.get(mid).equals(currentPlace)) 
      {return peers.get(mid);} 
   if (peers.get(mid).equals(currentPlace) && len>mid+1) 
      {return peers.get(mid+1);}
   return null;
    
  }


  PlaceAddress first()
  {
  int len = peers.size();
  PlaceAddress f = peers.get(0);
  if (!f.equals(currentPlace)) 
	   {return f;}
  if (f.equals(currentPlace) && len>1) 
	   {return peers.get(1);}
  return null;   

  }
  
  
  private int getPeerIndex(PlaceAddress p)
  {
	  for(int i=0; i<peers.size();i++)
  	{
  		if(peers.get(i).equals(p))
  		{return i;}
  	}
	  return -1;
  }
  
  
  
  private void offlinePeer(PlaceAddress peer, Date time)
  {
   reception(); //I enable the reception  of messages for the father
   loginToService(getServiceIdentificator("PeerToPeer_v1.0"), "ezio", "ezio");
   Identificator serviceId = getServiceIdentificator("PeerToPeer_v1.0");
   InteractionContainer ic = new InteractionContainer(getServiceProtocol(serviceId));
   int index = getPeerIndex(peer);
	peers.remove(index);
    Object[] params = new Object[2];
	params[0] = peer;
	params[1] = time;
	ic.makeInteraction("RemoveIP", params); 
	try {
		sendMessageToServiceAgent(new Message<InteractionContainer>(getIdentificator(), serviceId, ic));
	} catch (CommunicationException e) {e.printStackTrace();}

  }
  
  
}
